﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using GurLoader.Preferences;
using Imgur.Net.Auth;
using Moq;
using NUnit.Framework;

namespace GurLoaderWPF.Test.Preferences
{
    [TestFixture]
    public class GurLoaderPreferencesTests
    {
        
        [Test]
        public void GetOpenWhenCompleteTest()
        {
            Mock<IFileOperations> mockFileOps = new Mock<IFileOperations>();

            string prefsJson = ResourceLoader.GetResourceText("Resources/preferences.json");
            
            mockFileOps.Setup(x=>x.FileExists(It.IsAny<string>())).Returns(true).Verifiable();
            mockFileOps.Setup(x => x.ReadAllText(It.IsAny<string>())).Returns(prefsJson).Verifiable();

            GurLoaderPreferences prefs = GurLoaderPreferences.Load(mockFileOps.Object);

            Assert.IsNotNull(prefs);
            Assert.IsTrue(prefs.OpenWhenComplete);

            mockFileOps.VerifyAll();
        }

        [Test]
        public void SetOpenWhenCompleteTest()
        {
            Mock<IFileOperations> mockFileOps = new Mock<IFileOperations>();

            string prefsJson = ResourceLoader.GetResourceText("Resources/preferences.json");

            mockFileOps.Setup(x => x.FileExists(It.IsAny<string>())).Returns(true).Verifiable();
            mockFileOps.Setup(x => x.ReadAllText(It.IsAny<string>())).Returns(prefsJson).Verifiable();

            GurLoaderPreferences prefs = GurLoaderPreferences.Load(mockFileOps.Object);

            Assert.IsNotNull(prefs);
            Assert.IsTrue(prefs.OpenWhenComplete);

            prefs.OpenWhenComplete = false;

            Assert.IsFalse(prefs.OpenWhenComplete);

            mockFileOps.VerifyAll();
        }

        [Test]
        public void SetOpenWhenCompleteNotifyTest()
        {
            Mock<IFileOperations> mockFileOps = new Mock<IFileOperations>();

            string prefsJson = ResourceLoader.GetResourceText("Resources/preferences.json");

            mockFileOps.Setup(x => x.FileExists(It.IsAny<string>())).Returns(true).Verifiable();
            mockFileOps.Setup(x => x.ReadAllText(It.IsAny<string>())).Returns(prefsJson).Verifiable();

            GurLoaderPreferences prefs = GurLoaderPreferences.Load(mockFileOps.Object);

            bool foundOWCChanged = false;
            int invokeCount = 0;
            ManualResetEvent mre = new ManualResetEvent(false);
            prefs.PropertyChanged += (sender, e) =>
            {
                invokeCount++;

                if ("OpenWhenComplete".Equals(e.PropertyName))
                {
                    foundOWCChanged = true;
                    mre.Set();
                }
            };

            Assert.IsNotNull(prefs);
            Assert.IsTrue(prefs.OpenWhenComplete);

            prefs.OpenWhenComplete = false;

            mre.WaitOne(1000*10); // 10s max wait

            Assert.IsFalse(prefs.OpenWhenComplete);
            Assert.IsTrue(foundOWCChanged);
            Assert.AreEqual(2, invokeCount);

            mockFileOps.VerifyAll();
        }

        [Test]
        public void GetUseAnonymousContextTest()
        {
            Mock<IFileOperations> mockFileOps = new Mock<IFileOperations>();

            string prefsJson = ResourceLoader.GetResourceText("Resources/preferences.json");

            mockFileOps.Setup(x => x.FileExists(It.IsAny<string>())).Returns(true).Verifiable();
            mockFileOps.Setup(x => x.ReadAllText(It.IsAny<string>())).Returns(prefsJson).Verifiable();

            GurLoaderPreferences prefs = GurLoaderPreferences.Load(mockFileOps.Object);

            Assert.IsNotNull(prefs);
            Assert.IsTrue(prefs.UseAnonymousContext);

            mockFileOps.VerifyAll();
        }

        [Test]
        public void SetUseAnonymousContextTest()
        {
            Mock<IFileOperations> mockFileOps = new Mock<IFileOperations>();

            string prefsJson = ResourceLoader.GetResourceText("Resources/preferences.json");

            mockFileOps.Setup(x => x.FileExists(It.IsAny<string>())).Returns(true).Verifiable();
            mockFileOps.Setup(x => x.ReadAllText(It.IsAny<string>())).Returns(prefsJson).Verifiable();

            GurLoaderPreferences prefs = GurLoaderPreferences.Load(mockFileOps.Object);

            Assert.IsNotNull(prefs);
            Assert.IsTrue(prefs.UseAnonymousContext);

            prefs.UseAnonymousContext = false;

            Assert.IsFalse(prefs.UseAnonymousContext);

            mockFileOps.VerifyAll();
        }

        [Test]
        public void SetUseAnonymousContextNotifyTest()
        {
            Mock<IFileOperations> mockFileOps = new Mock<IFileOperations>();

            string prefsJson = ResourceLoader.GetResourceText("Resources/preferences.json");

            mockFileOps.Setup(x => x.FileExists(It.IsAny<string>())).Returns(true).Verifiable();
            mockFileOps.Setup(x => x.ReadAllText(It.IsAny<string>())).Returns(prefsJson).Verifiable();

            GurLoaderPreferences prefs = GurLoaderPreferences.Load(mockFileOps.Object);

            bool foundChanged = false;
            int invokeCount = 0;
            ManualResetEvent mre = new ManualResetEvent(false);
            prefs.PropertyChanged += (sender, e) =>
            {
                invokeCount++;

                if ("UseAnonymousContext".Equals(e.PropertyName))
                {
                    foundChanged = true;
                    mre.Set();
                }
            };

            Assert.IsNotNull(prefs);
            Assert.IsTrue(prefs.UseAnonymousContext);

            prefs.UseAnonymousContext = false;

            mre.WaitOne(1000 * 10); // 10s max wait

            Assert.IsFalse(prefs.UseAnonymousContext);
            Assert.IsTrue(foundChanged);
            Assert.AreEqual(2, invokeCount);

            mockFileOps.VerifyAll();
        }

        [Test]
        public void GetRegistrationTokensNullTest()
        {
            Mock<IFileOperations> mockFileOps = new Mock<IFileOperations>();

            string prefsJson = ResourceLoader.GetResourceText("Resources/preferences.json");

            mockFileOps.Setup(x => x.FileExists(It.IsAny<string>())).Returns(true).Verifiable();
            mockFileOps.Setup(x => x.ReadAllText(It.IsAny<string>())).Returns(prefsJson).Verifiable();

            GurLoaderPreferences prefs = GurLoaderPreferences.Load(mockFileOps.Object);

            Assert.IsNotNull(prefs);
            Assert.IsNull(prefs.RegistrationTokens);

            mockFileOps.VerifyAll();
        }

        [Test]
        public void GetRegistrationTokensNotNullTest()
        {
            Mock<IFileOperations> mockFileOps = new Mock<IFileOperations>();

            string prefsJson = ResourceLoader.GetResourceText("Resources/preferencesWithRegistrationTokens.json");

            mockFileOps.Setup(x => x.FileExists(It.IsAny<string>())).Returns(true).Verifiable();
            mockFileOps.Setup(x => x.ReadAllText(It.IsAny<string>())).Returns(prefsJson).Verifiable();

            GurLoaderPreferences prefs = GurLoaderPreferences.Load(mockFileOps.Object);

            Assert.IsNotNull(prefs);
            Assert.IsNotNull(prefs.RegistrationTokens);

            mockFileOps.VerifyAll();
        }

        [Test]
        public void SetRegistrationTokensNullTest()
        {
            Mock<IFileOperations> mockFileOps = new Mock<IFileOperations>();

            string prefsJson = ResourceLoader.GetResourceText("Resources/preferencesWithRegistrationTokens.json");

            mockFileOps.Setup(x => x.FileExists(It.IsAny<string>())).Returns(true).Verifiable();
            mockFileOps.Setup(x => x.ReadAllText(It.IsAny<string>())).Returns(prefsJson).Verifiable();

            GurLoaderPreferences prefs = GurLoaderPreferences.Load(mockFileOps.Object);
            ManualResetEvent mre = new ManualResetEvent(false);
            prefs.PropertyChanged += (sender, e) =>
            {
                if ("RegistrationTokens".Equals(e.PropertyName))
                    mre.Set();
            };

            Assert.IsNotNull(prefs);
            Assert.IsNotNull(prefs.RegistrationTokens);

            prefs.RegistrationTokens = null;
            Assert.IsNull(prefs.RegistrationTokens);

            Assert.IsTrue(mre.WaitOne(1000 * 3), "Timeout waiting for property update notification.");
            mockFileOps.VerifyAll();
        }

        [Test]
        public void SetRegistrationTokensNotNullTest()
        {
            Mock<IFileOperations> mockFileOps = new Mock<IFileOperations>();

            string prefsJson = ResourceLoader.GetResourceText("Resources/preferences.json");

            mockFileOps.Setup(x => x.FileExists(It.IsAny<string>())).Returns(true).Verifiable();
            mockFileOps.Setup(x => x.ReadAllText(It.IsAny<string>())).Returns(prefsJson).Verifiable();

            GurLoaderPreferences prefs = GurLoaderPreferences.Load(mockFileOps.Object);
            ManualResetEvent mre = new ManualResetEvent(false);
            prefs.PropertyChanged += (sender, e) =>
            {
                if ("RegistrationTokens".Equals(e.PropertyName))
                    mre.Set();
            };

            Assert.IsNotNull(prefs);
            Assert.IsNull(prefs.RegistrationTokens);

            prefs.RegistrationTokens = new DefaultRegistrationTokenContext("aaaa", "bbbb", DateTime.Now);
            Assert.IsNotNull(prefs.RegistrationTokens);

            Assert.IsTrue(mre.WaitOne(1000*3), "Timeout waiting for property update notification.");
            mockFileOps.VerifyAll();
        }

        public void GetIsDirty()
        {
            Mock<IFileOperations> mockFileOps = new Mock<IFileOperations>();

            string prefsJson = ResourceLoader.GetResourceText("Resources/preferences.json");

            mockFileOps.Setup(x => x.FileExists(It.IsAny<string>())).Returns(true).Verifiable();
            mockFileOps.Setup(x => x.ReadAllText(It.IsAny<string>())).Returns(prefsJson).Verifiable();

            GurLoaderPreferences prefs = GurLoaderPreferences.Load(mockFileOps.Object);

            prefs.OpenWhenComplete = false;

            Assert.IsNotNull(prefs);
            Assert.IsFalse(prefs.OpenWhenComplete);
            Assert.IsTrue(prefs.IsDirty);

            mockFileOps.VerifyAll();
        }

        [Test]
        public void SetIsDirtyNotifyTest()
        {
            Mock<IFileOperations> mockFileOps = new Mock<IFileOperations>();

            string prefsJson = ResourceLoader.GetResourceText("Resources/preferences.json");

            mockFileOps.Setup(x => x.FileExists(It.IsAny<string>())).Returns(true).Verifiable();
            mockFileOps.Setup(x => x.ReadAllText(It.IsAny<string>())).Returns(prefsJson).Verifiable();

            GurLoaderPreferences prefs = GurLoaderPreferences.Load(mockFileOps.Object);

            bool foundChanged = false;
            int invokeCount = 0;
            ManualResetEvent mre = new ManualResetEvent(false);
            prefs.PropertyChanged += (sender, e) =>
            {
                invokeCount++;

                if ("IsDirty".Equals(e.PropertyName))
                {
                    foundChanged = true;
                    mre.Set();
                }
            };

            Assert.IsNotNull(prefs);
            Assert.IsTrue(prefs.UseAnonymousContext);

            prefs.UseAnonymousContext = false;

            mre.WaitOne(1000 * 10); // 10s max wait

            Assert.IsFalse(prefs.UseAnonymousContext);
            Assert.IsTrue(prefs.IsDirty);
            Assert.IsTrue(foundChanged);
            Assert.AreEqual(2, invokeCount);

            mockFileOps.VerifyAll();
        }
    }
}
